﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CommandManager : SingletonMono<CommandManager>
{

    Queue<CommandBase> mainCommands = new Queue<CommandBase>(); // 主操作队列：接收输入层的操作
    Stack<CommandBase> undoCommands = new Stack<CommandBase>(); // 待撤销操作栈：主操作队列消费后压入该栈
    Stack<CommandBase> redoCommands = new Stack<CommandBase>(); // 待重做操作栈：撤销操作后压入该栈

    public void RegisterCommand(CommandBase command)
    {
        mainCommands.Enqueue(command);
    }

    public void Reset()
    {
        ClearUndos();
        ClearRedos();
    }

    int DoCommand()
    {
        if (mainCommands.Count > 0)
        {
            CommandBase command = mainCommands.Dequeue();
            command.execute();
            if (redoCommands.Count > 0) //在撤销期间新操作会清空已有操作队列
            {
                //新操作执行后先清空栈再压栈，当前操作方式为只清空重做栈，即有新操作后，可以继续回退到更早的操作，但不可重做该新操作执行时已撤销的操作
                //ClearUndos();
                ClearRedos();
            }
            if (command.IsEnterQueue)
            {
                undoCommands.Push(command);
            }
        }
        return mainCommands.Count;
    }

    int UndoCommand()
    {
        if (undoCommands.Count > 0)
        {
            CommandBase command = undoCommands.Pop();
            command.undo();
            redoCommands.Push(command);
        }
        return undoCommands.Count;
    }

    int RedoCommand()
    {
        if (redoCommands.Count > 0)
        {
            CommandBase command = redoCommands.Pop();
            command.execute();
            undoCommands.Push(command);
        }
        return redoCommands.Count;
    }

    void ClearUndos()
    {
        if (undoCommands.Count > 0)
        {
            undoCommands.Clear();
        }
    }

    void ClearRedos()
    {
        if (redoCommands.Count > 0)
        {
            redoCommands.Clear();
        }
    }

    void FixedUpdate()
    {
        DoCommand();
    }

    public void Do()
    {
        DoCommand();
    }

    public void Undo()
    {
        UndoCommand();
    }

    public void Redo()
    {
        RedoCommand();
    }
    }
